package FlowGraph.Nodes;

import antlr.collections.AST;

import java.util.*;

import util.Line;
import FlowGraph.StatementInfo.StatementInfo;
import FlowGraph.*;
import FlowGraph.EdgeInfo.*;

//////////////////////////////////////////////////////////////////////////
//// SwitchBeginNode
/**
@author Ivan Jeukens
@version v 0.1 03/10/2001
*/
public class SwitchBeginNode extends FlowGraphNode {

    public SwitchBeginNode(AST statement) {
        super(statement, SWITCH_BEGIN);
        _expression = statement.getFirstChild();

        _caseEndNodes = new LinkedList();
        _statementInfo = new StatementInfo(this, _expression);

        _extractCases();
    }

    ///////////////////////////////////////////////////////////////////
    ////                        public methods                     ////

    public String toString() {
        return new String("switch("  + ")");
    }

    public void setSwitchEnd(SwitchEndNode node) {
        _switchEnd = node;
    }
    
    public SwitchEndNode getSwitchEnd() {
        return _switchEnd;
    }

    public AST getExpression() {
        return _expression;
    }

    public void setConditionLine(Line l) {
        _conditionLine = l;
    }

    public Line getConditionLine() {
        return _conditionLine;
    }
    
    public void setEndLine(Line l) {
        _endLine = l;
    }

    public Line getEndLine() {
        return _endLine;
    }

    public void addCaseEndNode(FlowGraphNode node) {
        _caseEndNodes.add(node);
    }

    public FlowGraphNode getCaseEndNode(int k) {
        return (FlowGraphNode) _caseEndNodes.get(k);
    }

    public int caseEndNodeSize() {
        return _caseEndNodes.size();
    }

    public void setCaseEndNode(int pos, FlowGraphNode node) {
        _caseEndNodes.set(pos, node);
    }

    public StatementInfo getStatementInfo() {
        return _statementInfo;
    }

    public int hasCaseExpr(AST expr) {
        for(int i = 0;i < _outputEdges.size();i++) {
            FlowGraphEdge edge = (FlowGraphEdge) _outputEdges.get(i);
            SwitchEdge einfo = (SwitchEdge) edge.getEdgeInfo();
            LinkedList conds = einfo.getConditions();
            for(int j = 0;j < conds.size();j++) {
                AST ast = (AST) conds.get(j);
                if(expr.equalsTree(ast)) return i;
            }
        }
        return -1;
    }

    // Partindo de um no, encontra a aresta que e input ao Switch End
    public FlowGraphEdge getLastEdge(FlowGraphNode firstnode) {
        LinkedList processed = new LinkedList();
        HashMap marked = new HashMap();
        processed.add(firstnode);
        marked.put(firstnode, null);
        while(processed.size() > 0) {
            FlowGraphNode node = (FlowGraphNode) processed.remove(0);
            for(int i = 0;i < node.outputSize();i++) {
                FlowGraphEdge edge = (FlowGraphEdge) node.getOutputEdge(i);
                if(edge.isBack() || edge.isException()) continue;
                FlowGraphNode to = edge.getTo();
                if(to == _switchEnd) return edge;
                if(!marked.containsKey(to)) {
                    marked.put(to, null);
                    processed.add(to);
                }
            }
        }
        return null;
    }
    
    // Dado um no, encontra a aresta que leva ao seu case end
    public FlowGraphEdge getCaseEndEdge(FlowGraphNode firstnode, 
            FlowGraphNode cend) {
        LinkedList processed = new LinkedList();
        HashMap marked = new HashMap();
        processed.add(firstnode);
        marked.put(firstnode, null);
        while(processed.size() > 0) {
            FlowGraphNode node = (FlowGraphNode) processed.remove(0);
            for(int i = 0;i < node.outputSize();i++) {
                FlowGraphEdge edge = (FlowGraphEdge) node.getOutputEdge(i);
                if(edge.isBack() || edge.isException()) continue;
                FlowGraphNode to = edge.getTo();
                if(to == cend) return edge;
                if(!marked.containsKey(to)) {
                    marked.put(to, null);
                    processed.add(to);
                }
            }
        }
        return null;
    }

    ///////////////////////////////////////////////////////////////////
    ////                      private methods                      ////

    private void _extractCases() {
        _casesAST = new LinkedList();

        AST ast = _expression.getNextSibling();
        ast = ast.getFirstChild();
        while(ast != null) {
            _casesAST.add(ast);
            ast = ast.getNextSibling();
        }
    }

    ///////////////////////////////////////////////////////////////////
    ////                      private variables                    ////

    private AST _expression;
    private LinkedList _casesAST;
    private SwitchEndNode _switchEnd;

    // O no que encerra um case ... e usado pelo codegen
    private LinkedList _caseEndNodes;
 
    private Line _conditionLine;
    private Line _endLine;

    private StatementInfo _statementInfo;
}
